<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    /* 概念：一个函数对周围状态的引用捆绑在一起，内层函数中访问到其外层函数的作用域
    说人话：闭包（Closure） = 内层函数 + 外层函数的变量
    闭包作用：封闭数据，提供操作，外部也可以访问函数内部的变量
    闭包很有用，因为它允许将函数与其所操作的某些数据（环境）关联起来
    闭包可能引起的问题：内存泄漏

    简单写法:
    function outer() {
      let a = 10       // 外层变量
      function fn() {  // 内层函数  （缺一不可）
        console.log(a)
      }
      fn()
    }
    outer() */

    // 闭包作用：封闭数据，提供操作，外部也可以访问函数内部的变量
    // 闭包的基本格式：
    // 常见的闭包的形式    外部也可以访问使用 函数内部的变量
    /* function outer() {
      let a = 10  // 外界想要使用这个10     
      function fn() {
        console.log(a)
      }
      return fn
    }
    // 外界想要使用这个10
    // outer()  ===  fn === function fn()
    // const fun = function fn()
    const fun = outer()
    fun()  // 调用函数 */

    // 简约写法
    function outer() {
      let a = 10  // 外界想要使用这个10
      return function fn() {
        console.log(a)
      }
    }
    const fun = outer()
    fun()  // 调用函数


    // 闭包应用：实现数据的私有
    // 比如，我们要做一个统计函数调用次数，函数调用一次，就++

    // 普通形式  统计函数调用次数
    /* let i = 0
    function fn() {
      i++
      console.log(`函数被调用了${i}次`)  // 但是这个 i 是全局变量，很容易被修改
    }
    fn()  // 1
    fn()  // 2
    fn()  // 3
    i = 100
    fn()  // 101
    fn()  // 102
     */
    // 因为这个 i 是全局变量，很容易被修改
    // 闭包形式  统计函数调用次数
    function count() {
      let i = 0
      function fn() {
        i++
        console.log(`函数被调用了${i}次`)
      }
      return fn
    }
    const result = count()
    // 全局不会被回收 global ——> result ——> count() ——> fn() ——> i++ ——> let i = 0
    // 标记清除法，从全局可以找到 i，不会被回收，但是 i 已经被执行完了，导致内存泄漏
    result()  // 1
    result()  // 2
    i = 1000
    result()  // 3 无影响
    result()  // 4 无影响
    // 实现了数据私有，无法直接修改 i
  </script>
</body>

</html>